﻿using System;
using System.Collections.Generic;
using System.Web;

namespace Limestone
{
    public class PageProvider : IPageProvider
    {
        public IStorage Storage { get; set; }
        public IGetCurrentUserId GetCurrentUserId { get; set; }
        public IPageStubCache PageStubCache { get; set; }

        public PageProvider(IStorage storage, IGetCurrentUserId getCurrentUserId, IPageStubCache pageStubCache)
        {
            Storage = storage;
            GetCurrentUserId = getCurrentUserId;
            PageStubCache = pageStubCache;
        }



        /// <summary>
        /// Returns the current page
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public IPage GetCurrentPage(HttpContext context)
        {
            var path = context.Request.Url.PathAndQuery;

            var page = Storage.GetPage(path.Substring(context.Request.ApplicationPath.Length - 1));
            return page;
        }

        /// <summary>
        /// Loads and returns a full page object.
        /// For quick look ups, use GetPageStub instead
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public IPage Get(string path)
        {
            if (!path.StartsWith("/"))
                path = "/" + path;
            var page = Storage.GetPage(path);
            return page;
        }
        
        /// <summary>
        /// Loads a full page from a stub
        /// </summary>
        /// <param name="stub"></param>
        /// <returns></returns>
        public IPage ExpandToPage(IPageStub stub)
        {
            var page = Get(stub.Path);
            return page;
        }



        /// <summary>
        /// persists the page to storage
        /// </summary>
        /// <returns></returns>
        public IPage Save(IPage page)
        {
            page.Path = CleanUpPath(page.Path);

            page.TemplatePath = page.TemplatePath.ToLower().Replace(".template", "");

            page.Modified = new DateTime();
            page.ModifiedBy = GetCurrentUserId.CurrentUserId;
            if(string.IsNullOrEmpty(page.CreatedBy))
                page.CreatedBy = GetCurrentUserId.CurrentUserId;

            // TODO unique name in this parent

            if (!Storage.IsValidPageName(page.Name))
                return null;
            
            // delegate to storage provider
            var returnPage = Storage.SavePage(page);

            if (!PageStubCache.IsCached(returnPage.Path))
            {
                // insert the stub in the cache and update the navigation file
                PageStubCache.AddPageStub(ToPageStub(page), page.ParentPath);
            }
            return returnPage;
        }

        /// <summary>
        /// Creates a new page beneath the current page
        /// </summary>
        /// <param name="parentPage"> </param>
        /// <param name="title"></param>
        /// <returns></returns>
        public IPage CreateChildPage(IPage parentPage, string title)
        {
            var child = new Page(title);
            child.Path = parentPage.Path + "/" + child.Name;

            return child;
        }

        /// <summary>
        /// Returns the parent page
        /// </summary>
        /// <returns></returns>
        public IPage GetParent(IPage page)
        {
            if (page.ParentPath == "")
                return null;

            return Storage.GetPage(page.ParentPath);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="page"> </param>
        /// <param name="newParentPath"></param>
        public bool Move(IPage page, string newParentPath)
        {
            var oldPath = page.Path;
            if (Storage.MovePage(page, newParentPath))
            {
                // update navigation cache
                PageStubCache.MovePageStub(oldPath, newParentPath);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="page"> </param>
        /// <param name="targetParentPath"></param>
        public bool Copy(IPage page, string targetParentPath)
        {
            return Storage.CopyPage(page, targetParentPath);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="page"> </param>
        /// <param name="targetParentPage"></param>
        public bool Copy(IPage page, IPage targetParentPage)
        {
            return Storage.CopyPage(page, targetParentPage);
        }

        public bool Delete(string pagePath)
        {
            return Delete(Get(pagePath));
        }

        public bool Delete(IPage page)
        {
            var pagePath = page.Path;
            page.Deleted = new DateTime();
            page.DeletedBy = GetCurrentUserId.CurrentUserId;

            if (!Storage.DeletePage(page))
            {
                return false;
            }

            PageStubCache.RemovePageStub(pagePath);
            return true;
        }

        public IEnumerable<IPageStub> GetChildPages(string pagePath, bool excludeHidden)
        {
            return PageStubCache.GetChildPageStubsFor(pagePath);
        }

        public IEnumerable<IPageStub> GetChildPages(IPage page, bool excludeHidden)
        {
            return PageStubCache.GetChildPageStubsFor(page.Path);
        }

        public IPageStub ToPageStub(IPage page)
        {
            return new PageStub(page.Name, page.Path, page.Title, page.TemplatePath, page.Hidden);
        }

        private string CleanUpPath(string path)
        {
            if (path.StartsWith("//"))
                path = path.Substring(1);
            return path;
        }
    }

}
